/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.huawei.health.ecology.fa.central.processor;

import com.huawei.health.ecology.fa.central.data.IntentOptions;
import com.huawei.health.ecology.fa.central.request.ProxyRegisterRequest;
import com.huawei.health.ecology.fa.central.request.StartAbilityRequest;
import com.huawei.health.ecology.fa.central.response.CentralResponseCode;
import com.huawei.health.ecology.fa.central.response.QueryUniqueIdResponse;
import com.huawei.health.ecology.fa.utils.LogUtil;
import com.huawei.healthecology.data.utils.ConditionOperation;
import com.huawei.healthecology.data.utils.OptionalX;
import com.huawei.healthecology.processor.HealthEcologyProcessor;

import lombok.AllArgsConstructor;
import lombok.Builder;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.app.Context;
import ohos.data.DatabaseHelper;
import ohos.data.preferences.Preferences;
import ohos.utils.net.Uri;

import java.util.Locale;
import java.util.Optional;
import java.util.UUID;

/**
 * The processor for ability context related operations
 */
@Builder
@AllArgsConstructor
public class AbilityOperationProcessor implements HealthEcologyProcessor {
    private static final String TAG = "AbilityOperationProcessor";

    private static final String UNIQUE_ID = "uniqueId";

    private static final String FILE_NAME = "common_db";

    private static final String SEPARATOR = "-";

    private static final String URL = "url";

    private static final String FLAGS = "flags";

    private static final String URI = "uri";

    private static final String PARAMS = "params";

    private static final String UUID_KEY = "uuid";

    private static final String KEY_FROM_APP = "&fromApp=";

    private static final String PROXY_REGISTER_URI = "hilink://hilinksvc.huawei.com/device?action=deviceAdd&prodId=";

    private final Context context;

    private String uniqueId;

    @Override
    public void initProcessor() {
        setUniqueId();
    }

    @Override
    public void releaseResource() {
    }

    @Override
    public void destroyProcessor() {
    }

    /**
     * Gets unique id.
     *
     * @return the response contains unique id
     */
    public QueryUniqueIdResponse getUniqueId() {
        return Optional.ofNullable(uniqueId)
            .map(uniqueIdVariable -> QueryUniqueIdResponse.builder()
                .responseCode(CentralResponseCode.OPERATION_SUCCESS)
                .uniqueId(uniqueIdVariable)
                .build())
            .orElse(QueryUniqueIdResponse.builder()
                .responseCode(CentralResponseCode.OPERATION_FAILED)
                .uniqueId(uniqueId)
                .build());
    }

    private void setUniqueId() {
        DatabaseHelper databaseHelper = new DatabaseHelper(context);
        Preferences preferences = databaseHelper.getPreferences(FILE_NAME);
        Optional.ofNullable(preferences).ifPresent(preferencesVariable -> {
            uniqueId = Optional.of(preferencesVariable.getString(UNIQUE_ID, ""))
                .filter(uniqueIdVariable -> !uniqueIdVariable.isEmpty())
                .orElse(UUID.randomUUID().toString().replace(SEPARATOR, "").toLowerCase(Locale.ROOT));
            preferencesVariable.putString(UNIQUE_ID, uniqueId);
            preferencesVariable.flush();
        });
    }

    /**
     * Start ability.
     *
     * @param startAbilityRequest the start ability request
     * @return the central response code
     */
    public CentralResponseCode startAbility(StartAbilityRequest startAbilityRequest) {
        String params = Optional.ofNullable(startAbilityRequest.getIntentParams()).orElse("");
        IntentOptions options = Optional.ofNullable(startAbilityRequest.getIntentOptions()).orElse(null);
        Optional<Intent> intentOptional = getStartAbilityIntent(startAbilityRequest.getBundleName(),
            startAbilityRequest.getAbilityName(), params, options);
        return intentOptional.map(intentVariable -> toStartAbility(intentVariable, options))
            .orElse(CentralResponseCode.OPERATION_FAILED);
    }

    private Optional<Intent> getStartAbilityIntent(String bundleName, String abilityName, String params,
        IntentOptions options) {
        if (bundleName == null || abilityName == null) {
            return Optional.empty();
        }
        Intent.OperationBuilder operationBuilder = new Intent.OperationBuilder().withDeviceId("");
        OptionalX.ofNullable(options)
            .ifPresent(optionsVariable -> {
                OptionalX.ofNullable(optionsVariable.getAction())
                    .ifPresent(operationBuilder::withAction)
                    .ifNotPresent(() -> operationBuilder.withAbilityName(abilityName).withBundleName(bundleName));
                Optional.ofNullable(optionsVariable.getUri()).map(Uri::parse).ifPresent(operationBuilder::withUri);
                Optional.of(optionsVariable.getFlags()).ifPresent(operationBuilder::withFlags);
            })
            .ifNotPresent(() -> LogUtil.error(TAG, "IntentOptions is null"));
        Intent intent = new Intent();
        Optional.ofNullable(params).ifPresent(paramsVariable -> intent.setParam(PARAMS, paramsVariable));
        intent.setOperation(operationBuilder.build());
        return Optional.of(intent);
    }

    private CentralResponseCode toStartAbility(Intent intent, IntentOptions intentOptions) {
        boolean isNewMission = (intent.getFlags() & Intent.FLAG_ABILITY_NEW_MISSION) == Intent.FLAG_ABILITY_NEW_MISSION;
        ConditionOperation.of(isNewMission)
            .ifExist(isNew -> {
                Optional.ofNullable(intentOptions)
                    .filter(IntentOptions::isTerminable)
                    .ifPresent(options -> context.terminateAbility());
                context.startAbility(intent, 0);
            })
            .ifNotExist(notNew -> context.startAbility(intent, 1));
        return CentralResponseCode.OPERATION_SUCCESS;
    }

    /**
     * Open url request central response code.
     *
     * @param url the url
     * @return the central response code
     */
    public CentralResponseCode openUrlRequest(String url) {
        Intent intent = new Intent();
        Operation operation = new Intent.OperationBuilder()
            .withUri(Uri.parse(url))
            .withFlags(Intent.FLAG_ABILITY_NEW_MISSION)
            .build();
        intent.setOperation(operation);
        context.startAbility(intent, 0);
        return CentralResponseCode.OPERATION_SUCCESS;
    }

    /**
     * Perform proxy register.
     *
     * @param proxyRegisterRequest the request
     * @return the central response code
     */
    public CentralResponseCode performProxyRegister(ProxyRegisterRequest proxyRegisterRequest) {
        return Optional.of(proxyRegisterRequest)
                .filter(request -> (request.getProductId() != null && request.getRegisterUuid() != null))
                .map(request -> obtainProxyRegisterIntent(request.getRegisterUuid(), request.getProductId()))
                .map(this::performProxyRegister)
                .orElse(CentralResponseCode.OPERATION_FAILED);
    }

    private Intent obtainProxyRegisterIntent(String uuid, String productId) {
        Operation operation = new Intent.OperationBuilder().withDeviceId("")
            .withFlags(Intent.FLAG_ABILITY_NEW_MISSION | Intent.FLAG_NOT_OHOS_COMPONENT)
            .withUri(Uri.parse(PROXY_REGISTER_URI + productId + KEY_FROM_APP + context.getBundleName()))
            .build();
        Intent intent = new Intent();
        intent.setOperation(operation);
        intent.setParam("uuid", uuid);
        return intent;
    }

    private CentralResponseCode performProxyRegister(Intent intent) {
        context.startAbility(intent, 0);
        context.terminateAbility();
        return CentralResponseCode.OPERATION_SUCCESS;
    }
}
